import { ErrorCodes } from '@boticord/consts'
import { BadRequestException, Inject, Injectable, Logger } from '@nestjs/common'
import DiscordOAuth2 from 'discord-oauth2'
import { AUTH_OPTIONS } from '../auth.constants'
import { AuthModuleOptions } from '../interfaces/auth-options.interface'

@Injectable()
export class DiscordAuthService {
  private readonly oauth: DiscordOAuth2
  private readonly logger = new Logger(DiscordAuthService.name)

  constructor(@Inject(AUTH_OPTIONS) private readonly options: AuthModuleOptions) {
    this.oauth = new DiscordOAuth2()

    this.oauth.on('debug', this.logger.debug.bind(this.logger))
    this.oauth.on('warn', this.logger.warn.bind(this.logger))
  }

  // get authorization token for a user from the discord oauth2 api
  async exchange(code: string, redirect: string) {
    try {
      return await this.oauth.tokenRequest({
        grantType: 'authorization_code',
        code,
        scope: this.options.scope,
        clientId: this.options.clientID,
        clientSecret: this.options.clientSecret,
        redirectUri: redirect,
      })
    } catch {
      throw new BadRequestException({ code: ErrorCodes.ThirdPartyFail })
    }
  }

  // get user data from the discord api
  async getUser(token: string) {
    try {
      return await this.oauth.getUser(token)
    } catch {
      throw new BadRequestException({ code: ErrorCodes.ThirdPartyFail })
    }
  }

  // get user guilds from the discord api
  async getGuilds(token: string) {
    try {
      return await this.oauth.getUserGuilds(token)
    } catch {
      throw new BadRequestException({ code: ErrorCodes.ThirdPartyFail })
    }
  }

  // refresh user token using the discord oauth2 api
  async refresh(refresh: string, redirect: string) {
    try {
      return await this.oauth.tokenRequest({
        grantType: 'refresh_token',
        refreshToken: refresh,
        scope: this.options.scope,
        clientId: this.options.clientID,
        clientSecret: this.options.clientSecret,
        redirectUri: redirect,
      })
    } catch {
      throw new BadRequestException({ code: ErrorCodes.ThirdPartyFail })
    }
  }
}
